import { camelize, isPlainObject, hasOwn, extend } from '../../util/index'
import { ASSET_TYPES  } from '../../util/constants'

const strats = Object.create(null)

function mergeAssets(
    parentVal,
    childVal
) {
    const res = Object.create(parentVal || null)
    if (childVal) {
        return extend(res, childVal)
    } else {
        return res
    }
}

ASSET_TYPES.forEach(function (type) {
    strats[type + 's'] = mergeAssets
})

const defaultStrat = function (parentVal, childVal) {
    return childVal === undefined
        ? parentVal
        : childVal
}



function normalizeProps(options) {
    const props = options.props
    if (!props) return
    const res = {}
    let i, val, name
    if (Array.isArray(props)) {
        i = props.length
        while (i--) {
            val = props[i]
            if (typeof val === 'string') {
                name = camelize(val)
                res[name] = { type: null }
            }
        }
    } else if (isPlainObject(props)) {
        for (const key in props) {
            val = props[key]
            name = camelize(key)
            res[name] = isPlainObject(val)
                ? val
                : { type: val }
        }
    }
    options.props = res
}

function normalizeDirectives(options) {
    const dirs = options.directives
    if (dirs) {
        for (const key in dirs) {
            const def = dirs[key]
            if (typeof def === 'function') {
                dirs[key] = { bind: def, update: def }
            }
        }
    }
}

export function mergeOptions(
    parent,
    child,
    vm
) {

    if (typeof child === 'function') {
        child = child.options
    }

    //规范Props属性格式
    normalizeProps(child)
    //规范Directives属性格式
    normalizeDirectives(child)

    if (!child._base) {

        //extends属性和child的写法是一样的，因此这里调用递归
        if (child.extends) {
            parent = mergeOptions(parent, child.extends, vm)
        }
        //mixins属性和child的写法是一样的，因此这里调用递归
        if (child.mixins) {
            for (let i = 0, l = child.mixins.length; i < l; i++) {
                parent = mergeOptions(parent, child.mixins[i], vm)
            }
        }
    }

    const options = {}
    let key
    for (key in parent) {
        mergeField(key)
    }
    for (key in child) {
        //因为上面已经完成了从父类属性合并到子类的操作，
        //因此这里需要一个判重,从子合并到父
        if (!hasOwn(parent, key)) {
            mergeField(key)
        }
    }
    function mergeField(key) {
        const strat = strats[key] || defaultStrat
        options[key] = strat(parent[key], child[key], vm, key)
    }
    return options
}



export function resolveAsset(
    options,
    type,
    id,
    warnMissing
) {
    if (typeof id !== 'string') {
        return
    }
    const assets = options[type]
    if (hasOwn(assets, id)) return assets[id]
    const camelizedId = camelize(id)
    if (hasOwn(assets, camelizedId)) return assets[camelizedId]

    const res = assets[id] || assets[camelizedId]
    if (warnMissing && !res) {
        console.error('找不到 ' + type.slice(0, -1) + ': ' + id)
    }
    return res
}
